mod transport;
mod client;
mod server;
#[cfg(test)]
mod transport_tests;
#[cfg(test)]
mod client_tests;
#[cfg(test)]
mod server_tests;

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(version, about = "SOCKS5 over WebSocket/TCP tunnel for SSH/SCP/SFTP")]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    Client {
        #[arg(long, default_value = "127.0.0.1:1080")]
        listen_addr: String,
        #[arg(long, default_value = "server.example.com:443")]
        server_addr: String,
        #[arg(long, default_value = "ws", value_parser = ["ws", "tcp"])]
        transport: String,
        #[arg(long)]
        no_tls: bool,
    },
    Server {
        #[arg(long, default_value = "0.0.0.0:443")]
        listen_addr: String,
        #[arg(long, default_value = "server-cert.pem")]
        cert: String,
        #[arg(long, default_value = "server-key.pem")]
        key: String,
        #[arg(long, default_value = "ws", value_parser = ["ws", "tcp"])]
        transport: String,
        #[arg(long)]
        no_tls: bool,
    },
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    env_logger::init();

    let cli = Cli::parse();
    match cli.command {
        Commands::Client {
            listen_addr,
            server_addr,
            transport,
            no_tls,
        } => {
            let config = client::Config {
                listen_addr,
                server_addr,
                transport,
                no_tls,
            };
            let (_shutdown_sender, shutdown_receiver) = tokio::sync::oneshot::channel();
            let (tx, _) = tokio::sync::oneshot::channel();
            client::start_client(config, shutdown_receiver, tx).await
        }
        Commands::Server {
            listen_addr,
            cert,
            key,
            transport,
            no_tls,
        } => {
            let config = server::Config {
                listen_addr,
                cert,
                key,
                transport,
                no_tls,
            };
            let (_shutdown_sender, shutdown_receiver) = tokio::sync::oneshot::channel();
            let (tx, _) = tokio::sync::oneshot::channel();
            server::start_server(config, shutdown_receiver, tx).await
        }
    }
}
